/**
*****************************************************************************************
*     Copyright(c) 2015, Realtek Semiconductor Corporation. All rights reserved.
*****************************************************************************************
* @file     private_beacon_server.c
* @brief    Source file for private beacon server model.
* @details  Data types and external functions declaration.
* @author   hector_huang
* @date     2020-08-04
* @version  v1.0
* *************************************************************************************
*/
#include "mesh_config.h"

#if MESH_PRB
#include "private_beacon_model.h"
#include "mesh_beacon.h"


static mesh_model_info_t prb_server_model;

static mesh_msg_send_cause_t private_beacon_server_send(mesh_model_info_p pmodel_info,
                                                        uint16_t dst, void *pmsg, uint16_t msg_len, uint16_t net_key_index,
                                                        uint32_t delay_time)
{
    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = pmsg;
    mesh_msg.msg_len = msg_len;
    mesh_msg.akf = 0;
    mesh_msg.net_key_index = net_key_index;
    mesh_msg.dst = dst;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

static mesh_msg_send_cause_t private_beacon_status(mesh_model_info_p pmodel_info,
                                                   uint16_t dst, uint16_t net_key_index, uint8_t private_beacon,
                                                   uint8_t random_update_interval_steps)
{
    private_beacon_status_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_PRIVATE_BEACON_STATUS);
    msg.private_beacon = private_beacon;
    msg.random_update_interval_steps = random_update_interval_steps;

    return private_beacon_server_send(pmodel_info, dst, &msg, sizeof(msg), net_key_index, 0);
}

static mesh_msg_send_cause_t private_gatt_proxy_status(mesh_model_info_p pmodel_info,
                                                       uint16_t dst, uint16_t net_key_index, uint8_t private_gatt_proxy)
{
    private_gatt_proxy_status_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_PRIVATE_GATT_PROXY_STATUS);
    msg.private_gatt_proxy = private_gatt_proxy;

    return private_beacon_server_send(pmodel_info, dst, &msg, sizeof(msg), net_key_index, 0);
}

static mesh_msg_send_cause_t private_node_identity_status(mesh_model_info_p pmodel_info,
                                                          uint16_t dst, uint16_t net_key_index, uint8_t status, uint16_t sub_net_key_index,
                                                          uint8_t private_identity)
{
    private_node_identity_status_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_PRIVATE_NODE_IDENTITY_STATUS);
    msg.status = status;
    msg.net_key_index = sub_net_key_index;
    msg.private_identity = private_identity;

    return private_beacon_server_send(pmodel_info, dst, &msg, sizeof(msg), net_key_index, 0);
}

static bool private_beacon_server_receive(mesh_msg_p pmesh_msg)
{
    bool ret = TRUE;
    uint8_t *pbuffer = pmesh_msg->pbuffer + pmesh_msg->msg_offset;
    //mesh_model_info_p pmodel_info = pmesh_msg->pmodel_info;

    switch (pmesh_msg->access_opcode)
    {
    case MESH_MSG_PRIVATE_BEACON_GET:
        if (pmesh_msg->msg_len == sizeof(private_beacon_get_t))
        {
            private_beacon_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                  mesh_node.features.prb,
                                  mesh_node.prb_random_update_interval / 10);
        }
        break;
    case MESH_MSG_PRIVATE_BEACON_SET:
        {
            private_beacon_set_t *pmsg = (private_beacon_set_t *)pbuffer;
            if (pmsg->private_beacon <= 1)
            {
                if (mesh_node.features.prb != pmsg->private_beacon)
                {
                    mesh_node.features.prb = pmsg->private_beacon;
                    pmsg->private_beacon ? private_beacon_start() : private_beacon_stop();
                    mesh_flash_store(MESH_FLASH_PARAMS_FEATURES, NULL);
                }
                if (pmesh_msg->msg_len == sizeof(private_beacon_set_t))
                {
                    mesh_node.prb_random_update_interval = pmsg->random_update_interval_steps;
                    mesh_node.prb_random_update_interval *= 10;
                    private_beacon_random_timer_update(mesh_node.prb_random_update_interval);
                    /* TODO: store private beacon random update interval */
                }

                private_beacon_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                      mesh_node.features.prb,
                                      mesh_node.prb_random_update_interval / 10);
            }
        }
        break;
    case MESH_MSG_PRIVATE_GATT_PROXY_GET:
        if (pmesh_msg->msg_len == sizeof(private_gatt_proxy_get_t))
        {
            private_gatt_proxy_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                      mesh_node.features.private_proxy);
        }
        break;
    case MESH_MSG_PRIVATE_GATT_PROXY_SET:
        if (pmesh_msg->msg_len == sizeof(private_gatt_proxy_set_t))
        {
            private_gatt_proxy_set_t *pmsg = (private_gatt_proxy_set_t *)pbuffer;
            if ((pmsg->private_gatt_proxy <= 1) &&
                (mesh_node.features.private_proxy != pmsg->private_gatt_proxy))
            {
                if (mesh_node.features.private_proxy != 2)
                {
                    mesh_node.features.private_proxy = pmsg->private_gatt_proxy;
                    mesh_flash_store(MESH_FLASH_PARAMS_FEATURES, NULL);

                    if (mesh_node.features.private_proxy == 0)
                    {
                        mesh_private_service_adv_stop();
                    }
                    else
                    {
                        mesh_private_service_adv_start();
                    }
                }
            }

            if (pmsg->private_gatt_proxy <= 2)
            {
                private_gatt_proxy_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                          mesh_node.features.private_proxy);
            }
        }
        break;
    case MESH_MSG_PRIVATE_NODE_IDENTITY_GET:
        if (pmesh_msg->msg_len == sizeof(private_node_identity_get_t))
        {
            private_node_identity_get_t *pmsg = (private_node_identity_get_t *)pbuffer;
            mesh_msg_stat_t status = MESH_MSG_STAT_SUCCESS;
            uint8_t private_identity = 2;
            uint16_t net_key_index = net_key_index_from_global(pmsg->net_key_index);
            if (mesh_node.net_key_num == net_key_index)
            {
                status = MESH_MSG_STAT_INVALID_NET_KEY_INDEX;
                private_identity = 0;
                private_node_identity_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                             status, pmsg->net_key_index, private_identity);
            }
            else
            {
                if (mesh_node.features.private_proxy < 2)
                {
                    private_identity = mesh_node.net_key_list[net_key_index].private_identity;
                }
                private_node_identity_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                             status, pmsg->net_key_index, private_identity);
            }
        }
        break;
    case MESH_MSG_PRIVATE_NODE_IDENTITY_SET:
        if (pmesh_msg->msg_len == sizeof(private_node_identity_set_t))
        {
            private_node_identity_set_t *pmsg = (private_node_identity_set_t *)pbuffer;
            mesh_msg_stat_t status = MESH_MSG_STAT_SUCCESS;
            uint8_t private_identity = 2;
            uint16_t net_key_index = net_key_index_from_global(pmsg->net_key_index);
            if (mesh_node.net_key_num == net_key_index)
            {
                status = MESH_MSG_STAT_INVALID_NET_KEY_INDEX;
                private_identity = 0;
                private_node_identity_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                             status, pmsg->net_key_index, private_identity);
            }
            else
            {
                if ((pmsg->private_identity < 2) && (mesh_node.features.private_proxy < 2))
                {
                    if (mesh_node.net_key_list[net_key_index].private_identity != pmsg->private_identity)
                    {
                        /* save flash ? */
                        mesh_node.net_key_list[net_key_index].private_identity = pmsg->private_identity;
                        if (pmsg->private_identity)
                        {
                            mesh_private_service_identity_adv_start();
                        }
                    }
                    private_identity = pmsg->private_identity;
                }
                private_node_identity_status(&prb_server_model, pmesh_msg->src, pmesh_msg->net_key_index,
                                             status, pmsg->net_key_index, private_identity);
            }
        }
        break;
    default:
        ret = FALSE;
        break;
    }
    return ret;
}

bool private_beacon_server_reg(void)
{
    prb_server_model.model_id = MESH_MODEL_PRIVATE_BEACON_SERVER;
    prb_server_model.model_receive = private_beacon_server_receive;
    return mesh_model_reg(0, &prb_server_model);
}
#endif

